package com.yhsoft.wxprogram.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.*;
import java.util.ArrayList;
import java.util.List;

public class CommonUtil {
    static String serialNo;

    public static WechatPayHttpClientBuilder getWechatPayHttpClientBuilder() throws Exception{
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                Files.newInputStream(Paths.get(ConstantPropertiesUtils.KEY)));

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();

        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(ConstantPropertiesUtils.PARTNER, new WechatPay2Credentials(ConstantPropertiesUtils.PARTNER,
                new PrivateKeySigner(CommonUtil.getSerialNumber(ConstantPropertiesUtils.CERT), merchantPrivateKey)),ConstantPropertiesUtils.APIV3KEY.getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号，可继续调用putMerchant添加商户信息

        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(ConstantPropertiesUtils.PARTNER);
// ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        X509Certificate certificate = verifier.getValidCertificate();
        List<X509Certificate> certificates = new ArrayList<>();
        certificates.add(certificate);

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(ConstantPropertiesUtils.PARTNER, CommonUtil.getSerialNumber(ConstantPropertiesUtils.CERT), merchantPrivateKey)
                .withWechatPay(certificates);
        // ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签
        return builder;
    }



    /**
     * 获取CA证书的序列号
     * @param certPath
     * @return
     */
    public static String getSerialNumber(String certPath) {
        if (StrUtil.isEmpty(serialNo)) {
            // 获取CA证书序列号
            X509Certificate certificate = CommonUtil.getCertificate(FileUtil.getInputStream(certPath));
            serialNo = certificate.getSerialNumber().toString(16).toUpperCase();

//            System.out.println("输出证书信息:\n" + certificate.toString());
//            // 输出关键信息，截取部分并进行标记
//            System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
//            System.out.println("版本号:" + certificate.getVersion());
//            System.out.println("签发者：" + certificate.getIssuerDN());
//            System.out.println("有效起始日期：" + certificate.getNotBefore());
//            System.out.println("有效终止日期：" + certificate.getNotAfter());
//            System.out.println("主体名：" + certificate.getSubjectDN());
//            System.out.println("签名算法：" + certificate.getSigAlgName());
//            System.out.println("签名：" + certificate.getSignature().toString());
        }
        System.out.println("serialNo:" + serialNo);
        return serialNo;
    }

    /**
     * 校验平台证书
     * @param inputStream
     * @return
     */
    public static X509Certificate getCertificate(InputStream inputStream) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate)cf.generateCertificate(inputStream);
            cert.checkValidity();
            return cert;
        } catch (CertificateExpiredException var3) {
            throw new RuntimeException("证书已过期", var3);
        } catch (CertificateNotYetValidException var4) {
            throw new RuntimeException("证书尚未生效", var4);
        } catch (CertificateException var5) {
            throw new RuntimeException("无效的证书", var5);
        }
    }
}
